package oa.hleast.xswl.service.clockin.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import oa.hleast.common.utils.CalculateDistanceUtil;
import oa.hleast.common.web.exception.BizException;
import oa.hleast.xswl.common.constant.CommonConstant;
import oa.hleast.xswl.mapper.clockin.UmsClockInMapper;
import oa.hleast.xswl.mapper.place.PlaceInfoMapper;
import oa.hleast.xswl.pojo.domain.clockin.UmsClockIn;
import oa.hleast.xswl.pojo.domain.place.CmsPlaceInfo;
import oa.hleast.xswl.pojo.form.clockin.UmsClockInForm;
import oa.hleast.xswl.pojo.vo.clockin.UmsClockInVo;
import oa.hleast.xswl.service.IUmsUserService;
import oa.hleast.xswl.service.clockin.IClockInService;
import org.apache.commons.lang3.ObjectUtils;
import org.gavaghan.geodesy.Ellipsoid;
import org.gavaghan.geodesy.GlobalCoordinates;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author 302
 */
@Service
@Transactional
@AllArgsConstructor
@Slf4j
public class IClockInServiceImpl extends ServiceImpl<UmsClockInMapper, UmsClockIn> implements IClockInService {

    private final UmsClockInMapper clockInMapper;
    private final IUmsUserService iUmsUserService;
//    private final IPlaceInfoService placeInfoService;
    private final PlaceInfoMapper placeInfoMapper;

    @Override
    public boolean add(UmsClockInForm form) {
        CmsPlaceInfo placeInfo = placeInfoMapper.selectById(form.getPlaceInfoId());
        if (ObjectUtils.isEmpty(placeInfo)) {
            throw new BizException("该地点不存在");
        }

        // 该地点是否打过卡
        if (this.isClockIn(form.getPlaceInfoId(), form.getUserId(), form.getSourceType())) {
            throw new BizException("该地点您已经打过卡了哦！");
        }

        // 距离检查 这里的精确性需要后期优化
        GlobalCoordinates source = new GlobalCoordinates(placeInfo.getLatitude().doubleValue(), placeInfo.getLongitude().doubleValue());
        GlobalCoordinates target = new GlobalCoordinates(form.getLatitude().doubleValue(), form.getLongitude().doubleValue());
        double distance = CalculateDistanceUtil.getDistanceMeter(source, target, Ellipsoid.WGS84);
        log.info("distance = {}", distance);

        BigDecimal absDistance = new BigDecimal(distance).abs();

        log.info("用户 userId = {} 打卡位置到地图点位的直线距离 doubleDistance = {}", form.getUserId(), absDistance);
        if (absDistance.doubleValue() > CommonConstant.DISTANCE_RANGE) {
            throw new BizException("您现在不在打卡范围内，请前往打卡位置打卡");
        }

        UmsClockIn clockIn = conversionToPojo(form);
        boolean save = this.save(clockIn);
        return save;
    }

    @Override
    public List<UmsClockInVo> findUserClockInLog(Long userId, String sourceType) {
        LambdaQueryWrapper<UmsClockIn> query = new LambdaQueryWrapper<UmsClockIn>()
                .eq(UmsClockIn::getUserId, userId)
                .eq(UmsClockIn::getSourceType, sourceType)
                .orderByDesc(UmsClockIn::getGmtCreate)
                .orderByDesc(UmsClockIn::getGmtModified);
        List<UmsClockIn> list = this.list(query);
        List<UmsClockInVo> voList = list.stream().map(this::conversionToVo).collect(Collectors.toList());

        log.info("voList = {}", voList);
        return voList;
    }

    @Override
    public boolean isClockIn(Long placeInfoId, Long userId, String sourceType) {
        QueryWrapper<UmsClockIn> condition = new QueryWrapper<UmsClockIn>()
                .eq("place_info_id", placeInfoId)
                .eq("user_id", userId)
                .eq("source_type", sourceType)
                .eq("deleted", false)
                .last("limit 1");
        Integer count = clockInMapper.selectCount(condition);
        if (count > 0) {
            return true;
        } else {
            return false;
        }
    }

    private UmsClockIn conversionToPojo(UmsClockInForm form) {
        UmsClockIn clockIn = new UmsClockIn();
        BeanUtil.copyProperties(form, clockIn);
        return clockIn;
    }

    public UmsClockInVo conversionToVo(UmsClockIn pojo) {
        UmsClockInVo vo = new UmsClockInVo();
        BeanUtil.copyProperties(pojo, vo);
        return vo;
    }
}
